﻿using System;
using System.Windows.Input;

namespace NoMvvm
{
    /// <summary>
    /// Class making hidden ICommand implementation happen
    /// </summary>
    internal sealed class Command : ICommand
    {
        private readonly string _name;
        private readonly ViewModel _viewModel;
        private readonly Action<dynamic> _action;
        private readonly PropertyObserver<ViewModel> _observer;

        public Command(string name, ViewModel viewModel, Action action)
            : this(name, viewModel, _ => action())
        { }

        public Command(string name, ViewModel viewModel, Action<dynamic> action)
        {
            _name = name;
            _viewModel = viewModel;
            _action = action;
            _observer = new PropertyObserver<ViewModel>(viewModel);
            _observer.RegisterHandler("Can" + _name, _ => CanExecuteChanged(this, EventArgs.Empty));
        }

        public bool CanExecute(object parameter)
        {
            dynamic result;
            _viewModel.TryGetMember("Can" + _name, out result);
            return result ?? true;
        }

        public event EventHandler CanExecuteChanged = delegate { };

        public void Execute(object parameter)
        {
            try
            {
                _action(parameter);
            }
            catch (Exception exc)
            {
                _viewModel.Rescue(exc);
            }
        }
    }
}
